--region NewFile_1.lua
--Author : zhoujibo
--Date   : 2015/5/23
--此文件由[BabeLua]插件自动生成


module('UBBElement',package.seeall)

TYPE_TEXT = 0
TYPE_RES = 1
TYPE_GROUP = 2
TYPE_PLACEHOLDER = 3
TYPE_LI_START = 4
TYPE_LI_END = 5
TYPE_SCALE_START = 6
TYPE_SCALE_END = 7
TYPE_TOUCH_START = 8
TYPE_TOUCH_END = 9
TYPE_PARA_START = 10
TYPE_PARA_END = 11
TYPE_LINEALIGN_START = 12
TYPE_LINEALIGN_END = 13






--根据元素，给出元素内部进一步的单词信息：宽度，单词分割和换行符情况
--返回结构：[{所属元素，[元素内部单词1....],[内部字符长度列表][内部字符高度列表]，转换内容}...]
--单词结构：[单词起始索引，单词完结索引，总宽度,sX,sY]
function getElementWordInfo(elements)
    local result = {}
    
    local sX = 1
    local sY = 1

    local scaleStack = {} --缩放s栈
    
    for _,element in pairs(elements)do
    
        local charWidths = {}
        local charHeights = {}
        local words = {}


        local eType = element[1]
        local content = nil
        local font = nil
        local fontSize = nil

        --处理s标签
        if eType == TYPE_SCALE_START then
            local addScaleX = element[2] or 1
            local addScaleY = element[3] or 1
            table.insert(scaleStack,{addScaleX,addScaleY})
            sX = sX*addScaleX
            sY = sY*addScaleY
        elseif eType == TYPE_SCALE_END then
            table.remove(scaleStack)
            sX = 1
            sY = 1
            for _,sInfo in pairs(scaleStack)do
                sX = sX*sInfo[1]
                sY = sY*sInfo[2]
            end
        end
        


        --把有内容的元素的内容组织成数组
        if eType == TYPE_TEXT then
            --初始化元素内容
            content = utf8.breakApart(table.concat(string.split(element[2],'\t'),' '))
            font = element[3]
            if font==nil or font=='' then font = DEFAULT_TTF_PATH end
            fontSize = element[4] or 20
        elseif eType == TYPE_RES then
            content = {element}
        elseif eType == TYPE_GROUP then
            content = element[2]
        end
        

        local charWidth,charHeight
        --计算内容中每个元素的宽度
        if eType == TYPE_TEXT then
            for _,currentChar in pairs(content)do
                local outlineSize = element[7] or 0
                charWidth,charHeight = UBBCache.getCharSize(font,fontSize,currentChar,outlineSize,sX,sY)
                table.insert(charWidths,charWidth)
                table.insert(charHeights,charHeight)
            end
        elseif eType == TYPE_RES or eType == TYPE_GROUP then
            for _,currentChar in pairs(content)do
                local scheme = currentChar[2]
                local url = currentChar[3]
                local params = currentChar[4]
                charWidth,charHeight = UBBStylePlugin.SCHEME_GETSIZE_DICT[scheme](url,params,sX,sY)
                table.insert(charWidths,charWidth)
                table.insert(charHeights,charHeight)
            end
        end

        
        local wordWidth = 0

        --分割单词
        if eType == TYPE_TEXT then
            local lastChar = nil
            local wordStartIndex = 0
            local i = nil
            for i,currentChar in pairs(content)do
                if lastChar==nil 
                    or currentChar == ' ' 
                    or currentChar == '\n' 
                    or currentChar == '\t' 
                    or currentChar == ','  
                    or currentChar == '[' 
                    or string.len(currentChar)>1 
                    or lastChar == ']'
                    or lastChar == '.' 
                    then
                    --结束之前的单词
                    if lastChar~=nil then
                        table.insert(words,{wordStartIndex,i-1,wordWidth,sX,sY})
                        --本身也是一个独立的单词
                        table.insert(words,{i,i,charWidths[i],sX,sY})
                        lastChar = nil
                    else
                        --开始新的单词
                        wordWidth = charWidths[i]
                        wordStartIndex = i
                        lastChar = currentChar
                    end
                else
                    wordWidth = wordWidth+charWidths[i]
                    lastChar = currentChar
                end
            end
            if lastChar ~= nil then
                table.insert(words,{wordStartIndex,#content,wordWidth,sX,sY})
            end
        elseif eType == TYPE_RES or eType == TYPE_GROUP then
            wordWidth = 0
            for _,charWidth in pairs(charWidths)do
                wordWidth = wordWidth+charWidth
            end
            table.insert(words,{1,#content,wordWidth,sX,sY})
        end
        table.insert(result,{element,words,charWidths,charHeights,content})
    end
    return result
end

--将元素列表按照行为单位拆分成段，一行有若干个段，每个段属于一个元素的某一部分
--在此处处理li标签
function convertElementsToSegments(elements,wordsinfo,maxW)
    --算法描述
    --a.当一个单词处于行首且无法放下时，截断单词拆分到下一行
    --b.当一个单词不处于行首且无法放下时，放到下一行处理
    --c.遇到Li_start时，如果不是行首则主动换行
    --d.遇到li_end时，如果不是行首主动换行
    --e.遇到段落开头时，如果不是行首则换行(段落是否要首尾有空行，像html页面一样？2015年5月19日zjb)
    --f.遇到段落末尾时，如果不是行首则换行
    local x = 0 --当前的填充水平位移
    local lines = {}
    local segs = {}

    local sX = 1
    local sY = 1


    local isLiStart = false --li开始,需要阅读之后的一个元素，并确定其宽度
    
    local blockStack = {} -- 缩进情况{缩进宽度}
    local blockWidth = 0 --左边的总缩进宽度
    
    local rightBlockWidth = 0 --左边的总缩进宽度


    local pStack = {} -- p标签嵌套情况
    local pAlign = nil

    local laStack = {} -- la标签的嵌套情况
    local lineAlign = nil
    
    
    
    local function startNewLine()
        table.insert(lines,segs)
        segs = {}
        if blockWidth>0 then
            table.insert(segs,{{TYPE_PLACEHOLDER,blockWidth},nil,nil,nil,sX,sY,pAlign,lineAlign})
        end
        x = blockWidth
    end

    for i,element in pairs(elements)do
        local eType = element[1]
        if eType == TYPE_LI_START then
            assert(not isLiStart,'cant be two continue li start!')
            isLiStart = true
            if #segs>1 or(#segs==1 and segs[1][1]~=TYPE_PLACEHOLDER)then
                --段数必须大于1或者是1的情况下但是第一个段的元素不是占位元素，才能开启新行
                startNewLine()
            end
        elseif eType == TYPE_LI_END then
            table.remove(blockStack)
            blockWidth = 0
            for _,liWidth in pairs(blockStack)do
                blockWidth = blockWidth+liWidth
            end
            blockWidth = math.min(maxW,blockWidth)
            startNewLine()
        elseif eType == TYPE_PARA_START then
            if x>blockWidth then
                startNewLine()
            end
            table.insert(pStack,pAlign)
            pAlign = element[2]
        elseif eType == TYPE_PARA_END then
            if x>blockWidth then
                startNewLine()
            end
            pAlign = table.remove(pStack)
        elseif eType == TYPE_LINEALIGN_START then
            table.insert(laStack,lineAlign)
            lineAlign = element[2]
        elseif eType == TYPE_PARA_END then
            lineAlign = table.remove(laStack)
        else
            local info = wordsinfo[i]
            local words = info[2]
            local charWidths = info[3]
            local content = info[5]
            for j,word in pairs(words)do
                local wordStartIndex = word[1]
                local wordEndIndex = word[2]
                local wordWidth = word[3]
                sX = word[4]
                sY = word[5]
                if wordEndIndex==wordStartIndex and content[wordStartIndex] == '\n' then
                    --遇到换行符号，直接换行
                    startNewLine()
                    table.insert(segs,{element,wordStartIndex,wordEndIndex,content,sX,sY,pAlign,lineAlign})
                elseif(x+wordWidth)<=maxW then
                    --能容纳下的，整个单词放入
                    table.insert(segs,{element,wordStartIndex,wordEndIndex,content,sX,sY,pAlign,lineAlign})
                    x = x+wordWidth
                else
                    --处理一行放不下的
                    if(x+wordWidth)> maxW then
                        --不是在行首的，放到下一行处理
                        startNewLine()
                    end
                    --放到下一行还是放不下的
                    if(x+wordWidth)> maxW then
                        --拆单词
                        local sepStartI =  nil
                        for ii = wordStartIndex,wordEndIndex do
                            local charWidth = charWidths[ii]
                            if x == blockWidth and(x+charWidth)>maxW then
                                --第一个字符就放不下的
                                if #segs>0 then
                                    --先结束当前行
                                    startNewLine()
                                end
                                --直接占据一整行
                                table.insert(segs,{element,ii,ii,content,sX,sY,pAlign,lineAlign})
                                startNewLine()
                                sepStartI = nil
                            elseif x==blockWidth and(x+charWidth)<=maxW then
                                sepStartI = ii
                                x = charWidth
                            elseif(x+charWidth)>maxW then
                                --截断，结束行
                                table.insert(segs,{element,sepStartI,ii-1,content,sX,sY,pAlign,lineAlign})
                                --开始新的段
                                startNewLine()
                                sepStartI = ii
                                x = x+charWidth
                            else
                                x = x+charWidth
                            end
                        end
                        if sepStartI~=nil then
                            table.insert(segs,{element,sepStartI,wordEndIndex,content,sX,sY,pAlign,lineAlign})
                        end
                    else
                        --直接放入
                        table.insert(segs,{element,wordStartIndex,wordEndIndex,content,sX,sY,pAlign,lineAlign})
                        x = x+wordWidth
                    end
                end
            end
            if isLiStart then
                --为li选定第一个元素
                local totalW = 0
                for _,w in pairs(charWidths)do 
                    totalW = totalW+w
                end
                assert(totalW>0,'cant be no width element after li!')
                table.insert(blockStack,totalW)
                --确认之后起行宽度
                blockWidth = math.min(maxW,blockWidth + totalW)
                isLiStart = false
            end
        end

    end
    if #segs>0 then
        table.insert(lines,segs)
    end
    if not UBBLabel.DEBUG_NOLINE_COMBINE then
        --合并同行同元素的文本，尽可能减少纹理的提交
        for i,segs in pairs(lines)do
            local combinedSegs = {}
            local combineSeg = nil
            for _,seg in pairs(segs)do
                if(seg[1][1]==TYPE_TEXT)then
                    local element,wordStartIndex,wordEndIndex,content,_,_ = unpack(seg)
                    if wordStartIndex == wordEndIndex and content[wordStartIndex] == '\n' then
                        --换行单独成段
                        table.insert(combinedSegs,seg)
                        combineSeg = nil
                    elseif combineSeg and combineSeg[1]==element and(combineSeg[3]+1)==(wordStartIndex)then
                        --同一个元素，正好首尾相连，合并
                        combineSeg[3] = wordEndIndex
                    else
                        table.insert(combinedSegs,seg)
                        combineSeg = seg
                    end
                else
                    table.insert(combinedSegs,seg)
                    combineSeg = nil
                end
            end
            lines[i] = combinedSegs
        end
    end

    return lines
end
--endregion
